package com.google.antranking.utils;


import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerPNames;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;


public class HttpRequestUtils {


	private HttpClient httpClient;

	private InputStream keystore;

	private String keypass;

	private String basicAuthentication = null;


	/**
	 * Send an http post request
	 * @param url
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public InputStream sendPostRequest(final String url,List<NameValuePair> params) throws Exception{


		final HttpPost post = new HttpPost(url); 


		if (basicAuthentication != null)
			post.addHeader("Authorization", "Basic "+this.basicAuthentication);

		post.addHeader("Content-Type","application/x-www-form-urlencoded");
		post.setEntity(new UrlEncodedFormEntity(params));


		return getResult(this.getHttpClient().execute(post, new BasicHttpContext()));
	}

	/**
	 * Send an Http get request
	 * @param url
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public InputStream sendGetRequest(String url,CharSequence[] params) throws Exception {

		// TODO Check 
		if (params.length != 0){
			if (!url.endsWith("?"))
				url = url+"?";

			for (int i=0;i<params.length;i++){

				url+=params[i];
				if (i != params.length -1)
					url+="&";
			}
		}
		
		
		final HttpGet get = new HttpGet(url);
		get.addHeader("Content-Type","application/x-www-form-urlencoded");
		if (basicAuthentication != null)
			get.addHeader("Authorization", "Basic "+this.basicAuthentication);

		return getResult(this.getHttpClient().execute(get, new BasicHttpContext()));
	}


	/**
	 * Analyse Http Response and throw Exception if response is bad
	 * @param httpResponse
	 * @return
	 * @throws Exception
	 */
	private InputStream getResult(final HttpResponse httpResponse) throws Exception{
		
		if ((httpResponse.getStatusLine().getStatusCode() >= 200 )&&
				(httpResponse.getStatusLine().getStatusCode() < 300 ))

			return httpResponse.getEntity().getContent();
		else 

			throw new Exception(
				"Http Error Code "+
				httpResponse.getStatusLine().getStatusCode()+
				" "+convertStreamToString(httpResponse.getEntity().getContent()));

	}

	/**
	 * Http request parameters configuration
	 * @return
	 */
	private HttpParams createHttpParam(){

		final HttpParams params;   params = new BasicHttpParams();  
		params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 1); 
		params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(1));  
		params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);

		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);  
		HttpProtocolParams.setContentCharset(params, "utf8"); 

		return params;

	}


	/**
	 * Create and configure Http connection
	 * @return
	 */
	private HttpClient createConnectionManager(){

		final SchemeRegistry schemeRegistry = new SchemeRegistry();  
		schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));  
		
		if (keystore != null)
			schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(
				keystore,
				keypass), 8090));  
		else{
			try{
				
				final KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
				trustStore.load(null, null);
			
				final TrustSSLSocketFactory  sf = new TrustSSLSocketFactory(trustStore);
				sf.setHostnameVerifier(TrustSSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
				schemeRegistry.register(new Scheme("https", sf, 443));
			}
			catch(Exception e){
				e.printStackTrace();
			}
		}
		
		final HttpParams params = this.createHttpParam();
		final ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry);

		return new DefaultHttpClient(manager, params);  
	}

	
	
	final static public  String convertStreamToString(InputStream is) throws Exception {

		final BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		final StringBuilder sb = new StringBuilder();

		String line = null;
		while ((line = reader.readLine()) != null) {
			sb.append(line);
		}

		is.close();

		return sb.toString();
	}

	public HttpClient getHttpClient(){
		if (this.httpClient == null)
			this.httpClient =  this.createConnectionManager();
		return this.httpClient;
	}


	public void setBasicAuthentication(String username, String userpass){
		this.basicAuthentication = new String(Base64.encodeToString((username+":"+userpass).getBytes(),false));
	}

	public void setKeypass(String keypass){
		this.keypass = keypass;
	}

	public void setKeystore(InputStream keystore){
		this.keystore = keystore;
	}

}
